package cn.com.generaldata.os.service.impl;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.impl.sql.SqlTemplate;
import org.nutz.lang.Mirror;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import cn.com.generaldata.jsme_indicator_system.entity.Indicator;
import cn.com.generaldata.jsme_indicator_system.entity.ReportDetailNz;
import cn.com.generaldata.jsme_indicator_system.entity.ReportNz;
import cn.com.generaldata.jsme_indicator_system.entity.ReportTypeNz;
import cn.com.generaldata.jsme_indicator_system.entity.UnitNz;
import cn.com.generaldata.jsme_indicator_system.util.Constants;
import cn.com.generaldata.jsme_indicator_system.util.Constants.INDICATORTYPE;
import cn.com.generaldata.os.pojo.Area;
import cn.com.generaldata.os.service.common.AreaService;
import cn.com.generaldata.os.service.impl.HibernateInterceptor.InterceptorEvent;
import cn.com.generaldata.os.util.DefaultPasswordEncoder;

import com.IndicatorGisWSInterface;
import com.IndicatorGisWSService;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;

@Service
public class CommonXmlReport {

	
	private static Logger log = LoggerFactory.getLogger(CommonXmlReport.class);
	
	@Value("${gjme.serviceId}")
	private String serviceId;
	@Value("${gjme.username}")
	private String username;
	@Value("${gjme.password}")
	private String password;
	//专网接口地址
	@Value("${gjme.projectUrl}")
	private String serviceUrl;
	//外网接口地址
	@Value("${gjme.projectWebUrl}")
	private String serviceWebUrl;	
	@Value("${gjme.runMode}")
	private String runMode;
	@Value("${projectRunMode}")
	private String projectRunMode;
	@Autowired
	private Dao dao;

	@Autowired
	private SqlTemplate sqlTemplate;
	
	@Autowired
	private AreaService areaService;

	private final Mirror<ReportDetailNz> mirrorReportDetail = Mirror.me(ReportDetailNz.class);

	/**
	 * 生成加密密码
	 * @param username
	 * @param datetime
	 * @param password
	 * @return
	 */
	private String generalMD5PW(String username, String datetime, String password) {
		//先将密码md5散列化
		String encodePW = new DefaultPasswordEncoder("MD5").encode(password);
		//生成组合密码
		String encode = new DefaultPasswordEncoder("MD5").encode(serviceId + username + datetime + encodePW);
		return encode;
	}

	/**
	 * 调用service接口
	 * @param xmlFile
	 * @return
	 * @throws DocumentException
	 */
	private String excuteXml(String xmlFile) {

		if (!"LAN".equals(projectRunMode)){
			serviceUrl = serviceWebUrl;
		}
		
		//调用接口WebService地址
		URL url = null;
		try {
			url = new URL(serviceUrl);
		} catch (MalformedURLException e1) {
			e1.printStackTrace();
		}
		//用wsdl2java将接口WebService生成客户端调用的程序
		IndicatorGisWSService transferService = new IndicatorGisWSService(url);
		IndicatorGisWSInterface transferWSPort = transferService.getIndicatorGisWSPort();
		//调用接口服务(测试方法)，传入数据文件字符串，返回回执字符串信息
		//		String repsonseTest = transferWSPort.transferDataTest(xmlFile);
		
		
		//调用接口服务，传入数据文件字符串，返回回执字符串信息
		String repsonse = "";
		
		if ("test".equals(runMode)){	//测试环境调用
			repsonse = transferWSPort.transferDataTest(xmlFile);
		}else{
			repsonse = transferWSPort.transferData(xmlFile);
		}
		
		log.info("-----xmlFile------" + xmlFile);
		log.info("-----repsonse------" + repsonse);
		//回执信息，回执信息也可按dom结构解析
		return repsonse;
	}

	/**
	 * 调用接口
	 * @param report
	 * @param event
	 */
	public void createXMlReport(ReportNz report, InterceptorEvent event) {
		
			String error = "";
			String[] codeMsg = new String[2];
			//回执内容
			try {
				String response = excuteXml(createXMlData(report, event));
				System.out.println(response);
				codeMsg = getResponse(response);
			} catch (Exception e) {
				error = e.getMessage();
				// TODO Auto-generated catch block
				codeMsg[0] = "001";
				codeMsg[1] = "接口不通";
			}
			saveLog(report, codeMsg, error);

	}
	
	/**
	 * 自动生成报文
	 * @param report
	 * @param event
	 * @return String
	 */
	public String createXMlData(ReportNz report, InterceptorEvent event){
		//生成当前时间戳
		String datetime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH-mm-ss");
		Element excuteXML = DocumentHelper.createElement("excuteXML");
		Document document = DocumentHelper.createDocument(excuteXML);
		Element identityElement = excuteXML.addElement("identity");
		identityElement.addElement("serviceId").addText(serviceId);
		identityElement.addElement("username").addText(username);
		identityElement.addElement("time").addText(datetime);
		String md5pw = generalMD5PW(username, datetime, password);
		identityElement.addElement("password").addText(md5pw);
		Element businessElement = excuteXML.addElement("businessContent");
		Element subPackageElement = businessElement.addElement("subPackage");
		subPackageElement.addElement("id");
		if (event == InterceptorEvent.DELETE)
			subPackageElement.addElement("operateType").addText("0");
		else
			subPackageElement.addElement("operateType").addText("1");
		Element contentElement = subPackageElement.addElement("content");
		String cpXML = fillElement(report, event);
		contentElement.addText(cpXML);
		return document.asXML();
	}
	
	public void saveLog(ReportNz report, String[] codeMsg, String error) {
		//频度reportTypeNz.getTypeTime()
		String typeTime = report.getReportTimetype();
		String typeYearTime = report.getReportYearTime();
		//半年报seqYear
		if (Constants.INDICATOR_FULL_YEAR.equals(typeTime) && StringUtils.isNotBlank(typeYearTime)
				&& Constants.REPORT_HALF_YEAR.equals(Integer.valueOf(typeYearTime)))
			typeTime = Constants.HALF_YEAR + "";
		int seqYear = 1;
		String reportName = "";
		switch (Integer.valueOf(typeTime).intValue()) {
		case Constants.FULL_YEAR:
			seqYear = Constants.FULL_YEAR;
			reportName = report.getReportYear() + "年报";
			break;
		case Constants.HALF_YEAR:
			if ((Constants.REPORT_TIME_HALF_YEAR + "").equals(report.getReportYearTime()))
				reportName = report.getReportYear() + "下半年报";
			//上半年报
			else if ((Constants.REPORT_HALF_YEAR + "").equals(report.getReportYearTime()))
				reportName = report.getReportYear() + "上半年报";
			break;
		case Constants.MONTH_REPORT:
			seqYear = report.getMonth();
			reportName = report.getReportYear() + "年" + seqYear + "月";
			break;
		case Constants.QUARTER_REPORT:
			seqYear = report.getQuarter();
			reportName = report.getReportYear() + "年" + seqYear + "季";
			break;
		}
//		TransLogNz log = new TransLogNz();
//		log.setId(R.UU16());
//		log.setReportYear(report.getReportYear());
//		log.setReportId(report.getId());
//		log.setReportName(reportName + report.getReportType());
//		log.setUnitName(report.getReportUnit());
//		log.setCreateDate(new Date());
//		log.setCode(codeMsg[0]);
//		log.setContent(codeMsg[1]);
//		log.setErrorMsg(error);
//		dao.insert(log);
		
	}
	
	private String[] getResponse(String response) throws DocumentException {
		Document responseDocument = DocumentHelper.parseText(response);
		//根节点
		Element excuteXMLResponse = responseDocument.getRootElement();
		Element returnState = excuteXMLResponse.element("returnState");
		Element returnCode = returnState.element("returnCode");
		Element returnMessageElement = returnState.element("returnMessage");
		String[] codeMsg = new String[2];
		codeMsg[0] = returnCode.getText();
		codeMsg[1] = returnMessageElement.getText();
		return codeMsg;
	}

	/**
	 * 拼接Document
	 * @param rowsList
	 * @param numDigits
	 * @param areaMap
	 */
	private String fillElement(ReportNz report, InterceptorEvent event) {
		Element cpXML = DocumentHelper.createElement("cpXML");
		Document document = DocumentHelper.createDocument(cpXML);
		Element reportElement = cpXML.addElement("report");
		fillHeadElement(reportElement, report, event);
		return document.asXML();
	}

	/**
	 * 报文头
	 * @param reportElement
	 * @param report
	 * @param event
	 */
	private void fillHeadElement(Element reportElement, ReportNz report, InterceptorEvent event) {
		ReportTypeNz reportTypeNz = dao.fetch(ReportTypeNz.class, report.getReportTypeId());

		Area area = areaService.queryAreaById(report.getReportAreaId());
		
		UnitNz unitNz = dao.fetch(UnitNz.class, report.getUnitId());
		//表号
		reportElement.addElement("reportNo").addText(reportTypeNz.getTypeNo()+"");
		//单位的区划代码
		reportElement.addElement("regionCode").addText(area.getAreaCode()+"");
		//组织机构代码
		reportElement.addElement("unitCode").addText(StringUtils.isBlank(unitNz.getUnitInstitutionCode())?"":unitNz.getUnitInstitutionCode());
		//报表年份
		reportElement.addElement("reportYear").addText(report.getReportYear()+"");
		reportElement.addElement("contactPerson").addText(report.getReportUnitAdmin()+"");
		reportElement.addElement("userStatAdmin").addText(report.getReportStatAdmin()+"");
		reportElement.addElement("userStat").addText(report.getReportFillAdmin()+"");
		//频度
		String typeTime = reportTypeNz.getTypeTime();
		String typeYearTime = reportTypeNz.getTypeYearTime();
		//半年报seqYear
		if (Constants.INDICATOR_FULL_YEAR.equals(typeTime) && StringUtils.isNotBlank(typeYearTime)
				&& Constants.REPORT_HALF_YEAR.equals(Integer.valueOf(typeYearTime)))
			typeTime = Constants.REPORT_TIME_HALF_YEAR + "";
		reportElement.addElement("frequency").addText(typeTime);
		int seqYear = 1;
		switch (Integer.valueOf(typeTime).intValue()) {
		case Constants.FULL_YEAR:
			seqYear = Constants.FULL_YEAR;
			break;
		case Constants.HALF_YEAR:
			//下半年报
			if ((Constants.REPORT_TIME_HALF_YEAR + "").equals(report.getReportYearTime()))
				seqYear = Constants.REPORT_TIME_HALF_YEAR;
			//上半年报
			else if ((Constants.REPORT_HALF_YEAR + "").equals(report.getReportYearTime()))
				seqYear = Constants.REPORT_HALF_YEAR;
			break;
		case Constants.MONTH_REPORT:
			seqYear = report.getMonth();
			break;
		case Constants.QUARTER_REPORT:
			seqYear = report.getQuarter();
			break;
		}
		reportElement.addElement("seqYear").addText(seqYear + "");
		Element rowsElement = reportElement.addElement("rows");
		//删除操作没必要取内容
		if (event != InterceptorEvent.DELETE)
			fillBodyElement(rowsElement, report);
	}

	/**
	 * 报文体
	 * @param rowsElement
	 * @param report
	 */
	private void fillBodyElement(Element rowsElement, ReportNz report) {
		List<Indicator> indicatorList = queryReportTypeListIndicator(report.getReportTypeId());
		List<ReportDetailNz> detailList = dao.query(ReportDetailNz.class, Cnd.where("reportId", "=", report.getId()));
		Table<Integer, String, List<Indicator>> indicatorRowList = HashBasedTable.create();
		List<Indicator> list = Lists.newArrayList();
		//将同代码的指标放到一起（区分不同的属性）
		for (Indicator indicator : indicatorList) {
			if (indicatorRowList.get(indicator.getRow(), indicator.getCode()) == null) {
				list = Lists.newArrayList();
			} else {
				list = indicatorRowList.get(indicator.getRow(), indicator.getCode());
			}
			list.add(indicator);
			indicatorRowList.put(indicator.getRow(), indicator.getCode(), list);
		}
		for (ReportDetailNz detail : detailList) {
			Element rowElement = rowsElement.addElement("row");
			int rowIndex = detail.getRowIndex();
			//行号
			rowElement.addElement("rowIndex").addText(rowIndex + "");
			Map<String, List<Indicator>> row = indicatorRowList.row(rowIndex);
			Set<String> keySet = row.keySet();
			for (String code : keySet) {
				fillIndicator(detail, rowElement, row, code);
			}

		}
	}
	
	/**
	 * 拼接指标信息
	 * @param detail
	 * @param rowElement
	 * @param row
	 * @param code
	 */
	private void fillIndicator(ReportDetailNz detail, Element rowElement, Map<String, List<Indicator>> row, String code) {
		List<Indicator> codeList = row.get(code);
		Element indicatorElement = rowElement.addElement("indicator");
		indicatorElement.addElement("indicatorNo").addText(code);
		int i = 0;
		for (Indicator indicator : codeList) {
			Integer column = indicator.getTheColumn();
			if (i == 0)
				indicatorElement.addElement("indicatorMeaSure").addText(indicator.getMeasureCode()+"");
			Element typeElement = indicatorElement.addElement("type");
			if (indicator.getName().endsWith("-累计"))
				typeElement.addElement("indicatorType").addText(INDICATORTYPE.CURRENTTOTAL.getCode()+"");
			else if (indicator.getName().endsWith("-上年同期"))
					typeElement.addElement("indicatorType").addText(INDICATORTYPE.LASTCURRENT.getCode()+"");
			else if (indicator.getName().endsWith("-上期"))
				typeElement.addElement("indicatorType").addText(INDICATORTYPE.PRIOR.getCode()+"");
			else if (indicator.getName().endsWith("-上期累计"))
				typeElement.addElement("indicatorType").addText(INDICATORTYPE.PRIORTOTAL.getCode()+"");
			else if (indicator.getName().endsWith("-上年累计"))
				typeElement.addElement("indicatorType").addText(INDICATORTYPE.LASTTOTAL.getCode()+"");
			else
				typeElement.addElement("indicatorType").addText(INDICATORTYPE.CURRENT.getCode()+"");
			
			Object obj = mirrorReportDetail.getValue(detail, "f" + column);
			String value = (obj==null)? "": obj.toString();
			typeElement.addElement("indicatorValue").addText(value);
			i++;
		}
	}

	/**
	 * 报表指标
	 * @param typeId
	 * @return
	 */
	private List<Indicator> queryReportTypeListIndicator(String typeId) {
		String sql = "select idi.*,rti.row_index,rti.the_column,tm.code as measure_code from t_indicator idi left join t_measure tm on idi.measure_id=tm.id inner join t_report_type_indicator rti on idi.id=rti.indicator_id where rti.report_type_id=@typeId order by rti.row_index,the_column";
		Map params = Maps.newHashMap();
		params.put("typeId", typeId);
		List<Indicator> list = sqlTemplate.query(sql, params, Indicator.class);
		return list;
	}
}
